﻿using System;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Security;
using Restify;
using RestSharp;
using RestSharp.Contrib;

namespace FellowshipOne.API.Base
{
    public interface IFellowshipOneClient
    {
        F1OAuthTicket ExchangeRequestToken(F1OAuthTicket ticket, bool isStaging = false, bool useDemo = false);
        F1OAuthTicket Authorize(F1OAuthTicket ticket, string username, string password, LoginType loginType, bool isStaging = false, bool useDemo = false);
        F1OAuthTicket GetRequestToken(F1OAuthTicket ticket, bool isStaging = false, bool useDemo = false);
        F1OAuthTicket Authorize(F1OAuthTicket ticket, string username, string password, LoginType loginType, string baseUrl, bool isSecure = false, bool isStaging = false, bool useDemo = false);
        F1OAuthTicket BuildTicket(F1OAuthTicket ticket, string username, string password, Client client, string authUrl);
        F1OAuthTicket BuildTicket(F1OAuthTicket ticket, string authUrl);
    }

    public class FellowshipOneClient : IFellowshipOneClient
    {
        #region Methods
        public F1OAuthTicket ExchangeRequestToken(F1OAuthTicket ticket, bool isStaging = false, bool useDemo = false)
        {
            Client client = new Client(ticket);
            var authUrl = isStaging ? string.Format("https://{0}.staging.fellowshiponeapi.com/", ticket.ChurchCode) : string.Format("https://{0}.fellowshiponeapi.com/", ticket.ChurchCode);
            //var authUrl = string.Format("http://{0}.fellowshiponeapi.local/", ticket.ChurchCode);
            authUrl += "v1/Tokens/AccessToken";
            return BuildTicket(ticket, authUrl);
        }

        public F1OAuthTicket Authorize(F1OAuthTicket ticket, string username, string password, LoginType loginType, bool isStaging = false, bool useDemo = false)
        {
            Client client = new Client(ticket);
            var authUrl = isStaging ? string.Format("https://{0}.staging.fellowshiponeapi.com/", ticket.ChurchCode) : string.Format("https://{0}.fellowshiponeapi.com/", ticket.ChurchCode);
            authUrl += "v1/" + loginType.ToString() + "/AccessToken";
            return BuildTicket(ticket, username, password, client, authUrl);
        }

        public F1OAuthTicket GetRequestToken(F1OAuthTicket ticket, bool isStaging = false, bool useDemo = false)
        {
            Client client = new Client(ticket);
            var requestTokenUrl = isStaging ? string.Format("https://{0}.staging.fellowshiponeapi.com/", ticket.ChurchCode) : string.Format("https://{0}.fellowshiponeapi.com/", ticket.ChurchCode);
            //var requestTokenUrl = string.Format("http://{0}.fellowshiponeapi.local/", ticket.ChurchCode);
            requestTokenUrl += "v1/RequestToken";


            var oauthTicket = Client.GetRequestToken(ticket, "http://myapp.com", requestTokenUrl);
            ticket.AccessToken = oauthTicket.AccessToken;
            ticket.AccessTokenSecret = oauthTicket.AccessTokenSecret;
            return ticket;
        }

        public F1OAuthTicket Authorize(F1OAuthTicket ticket, string username, string password, LoginType loginType, string baseUrl, bool isSecure = false, bool isStaging = false, bool useDemo = false)
        {
            var client = new Client(ticket);
            var authUrl = string.Format("{0}://{1}.{2}/{3}/{4}/{5}", isSecure == true ? "https" : "http", ticket.ChurchCode, baseUrl, "v1", loginType, "AccessToken");
            return BuildTicket(ticket, username, password, client, authUrl);
        }

        public F1OAuthTicket BuildTicket(F1OAuthTicket ticket, string username, string password, Client client, string authUrl)
        {
            IRestResponse response = client.AuthorizeFirstParty(ticket, username, password, authUrl);

            if (response.StatusCode != HttpStatusCode.OK)
                throw new Exception(response.StatusDescription);
            else
            {
                var qs = HttpUtility.ParseQueryString(response.Content);
                ticket.AccessToken = qs["oauth_token"];
                ticket.AccessTokenSecret = qs["oauth_token_secret"];
                if (response.Headers.SingleOrDefault(x => x.Name == "Content-Location") != null)
                {
                    ticket.PersonURL = response.Headers.SingleOrDefault(x => x.Name == "Content-Location").Value.ToString();
                }
            }
            return ticket;
        }

        public F1OAuthTicket BuildTicket(F1OAuthTicket ticket, string authUrl)
        {
            IRestResponse response = Client.ExchangeRequestToken(ticket, authUrl);

            if (response.StatusCode != HttpStatusCode.OK)
                throw new Exception(response.StatusDescription);
            else
            {
                var qs = HttpUtility.ParseQueryString(response.Content);
                ticket.AccessToken = qs["oauth_token"];
                ticket.AccessTokenSecret = qs["oauth_token_secret"];
                if (response.Headers.SingleOrDefault(x => x.Name == "Content-Location") != null)
                {
                    ticket.PersonURL = response.Headers.SingleOrDefault(x => x.Name == "Content-Location").Value.ToString();
                }
            }
            return ticket;
        }

        private String SecureStringToString(SecureString value)
        {
            IntPtr bstr = Marshal.SecureStringToBSTR(value);

            try
            {
                return Marshal.PtrToStringBSTR(bstr);
            }
            finally
            {
                Marshal.FreeBSTR(bstr);
            }
        }

        #endregion Methods
    }
}
